<?php
if (!defined('APP_ID')) { die('No direct script access allowed'); }

/**
 * Data item abstraction
 */
class Data {
	private $_data = array();
	private $_id = 0;
	private $_language = null;
	private $_table = null;
	private $_column = null;
	private $_schema = null;

	public function __construct($schema, $table, $column, $id) {
		$this->_schema = self::getSchema($schema);
		$this->_table = $table;
		$this->_column = $column;
		$this->_id = $id;
		$this->_language = Config::get('schema_current', 'i18n');
		
		$check = true;
		
		if (!($this->_schema instanceof SimpleXMLElement)) { $check = false; }
		if (empty($this->_table)) { $check = false; }
		if (empty($this->_column)) { $check = false; }
		if (empty($this->_id)) { $check = false; }
		
		if (!$check) {
			throw new Node_Exception('Wrong arguments in constructor');
		}
	}

	/**
	 * Get value of fields
	 */
	public function get($fields_list = '') {
		if ($this->_id > 0) {
			$fields_list = self::cleanFieldsList($fields_list);
			$fields_list_arr = array();

			$all_fields = false;
			$single_field = false;
			if (empty($fields_list)) {
				$all_fields = true;
			} else {
				$fields_list_arr = explode(',', $fields_list);
				if (count($fields_list_arr) == 1) {
					$single_field = true;
				}
			}

			if ($single_field) {
				$fields = $this->_schema->xpath('/schema/form/field[@name="' . $fields_list_arr[0] . '"]');
			} else {
				$fields = $this->_schema->xpath('/schema/form/field');
			}

			$fields_arr = array();
			foreach ($fields as $field) {
				if (!$all_fields && !in_array(strtolower($field['name']), $fields_list_arr)) { continue; }
				if (isset($this->_data[(string)$field['name']])) { continue; } 
				$this->_data[(string)$field['name']] = '';

				$fields_arr_new = array();
				$fields_arr_new['name'] = $field['name'];
				$fields_arr_new['lang'] = false;
				if (isset($field['lang']) && (strtolower(trim($field['lang'])) == 'true')) {
					$fields_arr_new['lang'] = true;
				}
				$fields_arr[] = $fields_arr_new;
			}

			if (count($fields_arr) > 0) {
				$query = Query::factory('select')
					->table($this->_table)
					->fields('name,value')
					->where('%s=%d', $this->_column, $this->_id);

				$where = "";
				foreach ($fields_arr as $field_arr) {
					if (!empty($where)) {
						$where .= " OR ";
					}
					$where .= sprintf("((name='%s') AND ", $field_arr['name']);
					if ($field_arr['lang']) {
						$where .= sprintf("(language_code='%s'))", $this->_language);
					} else {
						$where .= sprintf("(language_code IS NULL))");
					}
				}
				$query->where('(%s)',  $where);

				$values = $query->execute()->rows();
				foreach ($values as $value) {
					$this->_data[(string)$value['name']] = $value['value'];
				}
			}

			if ($single_field) {
				if (isset($this->_data[(string)$fields_list])) {
					return $this->_data[(string)$fields_list];
				} else {
					return null;
				}
			} else {
				return $this->_data;
			}
		}
		
		return null;
	}

	/**
	 * Set value of fields
	 */
	public function setArr($fields) {
		foreach ($fields as $name => $value) {
			$this->setField($name, $value);
		}
	}

	/**
	 * Set value of single field
	 */
	public function set($name, $value) {
		$result = false;
		$fields = $this->_schema->xpath('/schema/form/field[@name="' . $name . '"]');
		if (count($fields) > 0) {
			$field = $fields[0];

			$multilang = false;
			if (isset($field['lang']) && (strtolower(trim($field['lang'])) == 'true')) {
				$multilang = true;
			}

			$query = Query::factory('select')
				->table($this->_table)
				->fields('id')
				->where('%s=%d', $this->_column, $this->_id)
				->where("name='%s'", $name);

			if ($multilang) {
				$query->where("language_code='%s'", $this->_language);
			} else {
				$query->where("language_code IS NULL");
			}
			$query->limit(1);
			$row = $query->execute()->row();

			$data = array();
			Query::data($data, 'value', $value);

			if ($row) {
				$query = Query::factory('update')
					->table($this->_table)
					->data($data)
					->where('id=%d', $row['id'])
					->execute();
				if (!$query->isError()) {
					$result = true;
				}
			} else {
				$language_code = null;
				if ($multilang) {
					$language_code = $this->_language;
				}
				Query::data($data, $this->_column, $this->_id, Query::DATA_INTEGER);
				Query::data($data, 'language_code', $language_code, Query::DATA_STRING);
				Query::data($data, 'name', $field['name'], Query::DATA_STRING);

				$id = Query::factory('update')
					->table($this->_table)
					->data($data)
					->where('id=%d', $row['id'])
					->execute()
					->getLastId();
				if ($id > 0) {
					$result = true;
				}
			}
		}
		
		return $result;
	}
	
	public function save($new = false) {
		$fields = $this->_schema->xpath('/schema/form/field');
		foreach ($fields as $field) {
			$multilang = false;
			if (isset($field['lang']) && (strtolower(trim($field['lang'])) == 'true')) {
				$multilang = true;
			}

			$empty_field = false;
			$field_name = 'data_' . $field['name'];
			$field_value = Input::post($field_name);
			if ((trim(strtolower($field['type'])) == 'file') && !intval($field_value)) {
				$empty_field = true;
			} else if (empty($field_value)) {
				$empty_field = true;
			}

			$curr_field = array();
			$cont = array();
			if (!$new) {
				$query = Query::factory('select')
					->table($this->_table)
					->fields('id')
					->where("(%s=%d) AND (name='%s')", $this->_column, $this->_id, $field['name']);

				if ($multilang) {
					$query->where("(language_code='%s')", Config::get('schema_current', 'i18n'));
				} else {
					$query->where("(language_code IS NULL)");
				}

				$curr_field = $query->execute()->row();
			}

			// If field was found then update it, else insert new field
			if ($curr_field) {
				Query::factory('update')
					->table($this->_table)
					->field('value', $field_value)
					->where("id=%d", $curr_field['id'])
					->execute();
			} else if (!$empty_field) {
				$query = Query::factory('insert')
					->table($this->_table)
					->field((string)$this->_column, $this->_id)
					->field('name', $field['name'])
					->field('value', $field_value);

				if ($multilang) {	
					$query->field('language_code', Config::get('schema_current', 'i18n'));
				}

				$query->execute();
			}
		}
		
		if (!$new) {
			$this->clear();
		}
	}

	public function clear() {
		$result = false;

		$fields = $this->_schema->xpath('/schema/form/field');

		$exist_fields_str = '';
		$file_fields_str = '';
		$lang_dependent_fields_str = '';
		$lang_independent_fields_str = '';

		foreach ($fields as $field) {
			$multilang = false;
			if (isset($field['lang']) && (strtolower(trim($field['lang'])) == 'true')) {
				$multilang = true;
			}

			// Collecting exist fields
			if (!empty($exist_fields_str)) {
				$exist_fields_str .= ",";
			}
			$exist_fields_str .= "'" . $field['name'] . "'";

			// Collecting file fields list
			if (trim(strtolower($field['type'])) == 'file') {
				if (!empty($file_fields_str)) {
					$file_fields_str .= ",";
				}
				$file_fields_str .= "'" . $field['name'] . "'";
			}

			// Collecting language dependent fields
			if ($multilang) {
				if (!empty($lang_dependent_fields_str)) {
					$lang_dependent_fields_str .= ",";
				}
				$lang_dependent_fields_str .= "'" . $field['name'] . "'";
			// Collecting language independent fields
			} else {
				if (!empty($lang_independent_fields_str)) {
					$lang_independent_fields_str .= ",";
				}
				$lang_independent_fields_str .= "'" . $field['name'] . "'";
			}
		}

		// Delete empty fields
		Query::factory('delete')
			->table($this->_table)
			->where("(%s=%d)", $this->_column, $this->_id)
			->where("((value IS NULL) OR (value=''))")
			->execute();

		// Delete not exist fields
		if (!empty($exist_fields_str)) {
			Query::factory('delete')
				->table($this->_table)
				->where("(%s=%d)", $this->_column, $this->_id)
				->where("(name NOT IN (%s))", $exist_fields_str)
				->execute();
		}

		// Delete empty file fields
		if (!empty($file_fields_str)) {
			Query::factory('delete')
				->table($this->_table)
				->where("(%s=%d)", $this->_column, $this->_id)
				->where("((name IN (%s)) AND (value=0))", $file_fields_str)
				->execute();
		}

		// Delete unused language independent fields
		if (!empty($lang_dependent_fields_str)) {
			Query::factory('delete')
				->table($this->_table)
				->where("(%s=%d)", $this->_column, $this->_id)
				->where("((name IN (%s)) AND (language_code IS NULL))", $lang_dependent_fields_str)
				->execute();
		}

		// Delete unused language dependent fields
		if (!empty($lang_independent_fields_str)) {
			Query::factory('delete')
				->table($this->_table)
				->where("(%s=%d)", $this->_column, $this->_id)
				->where("((name IN (%s)) AND (language_code IS NOT NULL))", $lang_independent_fields_str)
				->execute();
		}

		// Everything ok
		$result = true;

		return $result;
	}

	public static function getSchema($schema) {
		$result = null;
		
		if (is_string($schema)) {
			$schema_file = DATA_DIR . 'schemas/' . $schema;
			if (file_exists($schema_file)) {
				$result = simplexml_load_file($schema_file);
			}
		} else if ($schema instanceof SimpleXMLElement) {
			$result = $schema;
		}
		
		return $result;
	}

	public static function cleanFieldsList($str) {
		if (!empty($str)) {
			$str = strtolower($str);
			$str = preg_replace('/[\,]+/', ',', $str);
			$str = preg_replace('/^[\-]+/', '', $str);
			$str = preg_replace('/[\-]+$/', '', $str);
		} else {
			$str = null;
		}
		
		return $str;
	}
}
